﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Windows.Forms;
using CAGFIP.Edicao;
using CAGFIP.Jogo;
using CAGFIP.GUI.Dialogs;
using CAGFIP.Utils;

namespace CAGFIP.GUI
{
    public class ControladorGUI
    {
        #region Singleton

        private static ControladorGUI instance;

        private ControladorGUI() { }

        public static ControladorGUI Instance
        {
            get
            {
                if (instance == null)
                    instance = new ControladorGUI();
                return instance;
            }
        }

        #endregion

        #region Fields

        private JanelaPrincipal janelaPrincipal;
        private Configuracao configuracao;
        private CRUD_teste cRUD;
        private MenuInicial menuInicial;
        private Ranking_teste ranking;
        private TelaFinal telaFinal;
        private TelaPergunta telaPergunta;
        private string apelido;

        private bool telaDesistenciaAtiva;
        private bool tempoExpirado;
 
        #endregion

        #region Properties

        public Configuracao Configuracao
        {
            get { return this.configuracao ?? (this.configuracao = new Configuracao()); }
        }
        public CRUD_teste CRUD
        {
            //TODO: code refact
            get { return this.cRUD ?? (this.cRUD = new CRUD_teste()); }
        }
        public MenuInicial MenuInicial
        {
            get { return this.menuInicial ?? (this.menuInicial = new MenuInicial()); }
        }
        public Ranking_teste Ranking
        {
            //TODO: code refact
            get { return this.ranking ?? (this.ranking = new Ranking_teste()); }
        }
        public TelaFinal TelaFinal
        {
            get { return this.telaFinal ?? (this.telaFinal = new TelaFinal()); }
        }
        public TelaPergunta TelaPergunta
        {
            get { return this.telaPergunta ?? (this.telaPergunta = new TelaPergunta()); }
        }
        public string Apelido
        {
            set { this.apelido = value; }
        }

        #endregion

        #region ShowMethods

        public void Inicializar()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            janelaPrincipal = new JanelaPrincipal();
            ExibirMenuInicial();
            Application.Run(janelaPrincipal);
        }

        public void ExibirMenuInicial()
        {
            janelaPrincipal.Show();
            janelaPrincipal.TelaAtual = MenuInicial;
        }

        public void ExibirConfiguracao()
        {
            Configuracao.ConfigurarAssuntos(ControladorJogo.Instance.OnJogoIniciado());
            janelaPrincipal.TelaAtual = Configuracao;
        }

        public void ExibirPergunta(string enunciado, AlternativaCollection alternativas, int tempo)
        {
            TelaPergunta.InicializarRodada(enunciado, alternativas, tempo);
            janelaPrincipal.TelaAtual = TelaPergunta;
        }

        public void ExibirTelaFinal(JogoEndCode code)
        {
            janelaPrincipal.TelaAtual = TelaFinal;

            if (TelaFinal.InvokeRequired)
                TelaFinal.Invoke(new Action<JogoEndCode>(TelaFinal.DefinirMensagem), code);
            else
                TelaFinal.DefinirMensagem(code);
        }

        public void ExibirManipulacao()
        {
            List<Pergunta> perguntas;
            List<Assunto> assuntos;
            ControladorEdicao.Instance.ObterDados(out perguntas, out assuntos);

            CRUD.Configure(perguntas, assuntos);
            CRUD.Location = janelaPrincipal.Location;

            janelaPrincipal.Hide();
            CRUD.Show();

            /*
            ControladorEdicao.Instance.OnAutenticacaoOk(CRUD.Perguntas, CRUD.Assuntos);
            janelaPrincipal.TelaAtual = CRUD;*/
        }

        public void ExibirRanking()
        {
            try
            {
                //TODO: encapsulamento
                var rankings = ControladorRanking.RankingDAO.VisualizarRanking();

                Ranking.Configure(rankings);
                Ranking.Location = janelaPrincipal.Location;

                janelaPrincipal.Hide();
                Ranking.Show();

                /*
                ControladorRanking.Instance.OnVisualizacao(Ranking.Rank);
                janelaPrincipal.TelaAtual = Ranking;*/
            }
            catch
            {
                ExibirMensagemErro(Erros.ConexaoFalhou); //impossivel conectar ao SGBD
            }
        }

        public void ExibirAutenticacao()
        {
            AuthDialog dial = new AuthDialog();
            dial.ShowDialog();
        }

        public DialogResult ExibirConfirmacao(string titulo, string texto)
        {
            return MessageBox.Show(texto, titulo, MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
        }

        public void ExibirMensagemErro(string mensagemErro)
        {
            MessageBox.Show(mensagemErro, "Erro", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
        }

        #endregion

        internal void CarregarConfiguracoes(List<int> assuntosSelecionados, DificuldadeCode dificuldade)
        {
            try
            {
                ControladorJogo.Instance.OnConfiguracao(assuntosSelecionados, dificuldade,
                    ControladorGUI.Instance.TelaPergunta.chuteUpdateHandler,
                    ControladorGUI.Instance.TelaPergunta.puloUpdateHandler,
                    ControladorGUI.Instance.TelaPergunta.remAltUpdateHandler,
                    ControladorGUI.Instance.TelaPergunta.pontuacaoUpdateHandler
                    );
            }
            catch(Exception e)
            {
                ExibirMensagemErro(e.Message);
                ExibirMenuInicial();
                return;
            }

            string enunciadoPergunta;
            AlternativaCollection alternativas;
            int tempo;
            ControladorJogo.Instance.GetPergunta(out enunciadoPergunta, out alternativas, out tempo);
            ExibirPergunta(enunciadoPergunta, alternativas, tempo);
        }

        internal void OnTempoExpirado()
        {
            this.tempoExpirado = true;
            TelaPergunta.PararTimers();

            if (!this.telaDesistenciaAtiva)
            {
                this.tempoExpirado = false;
                MessageBox.Show("Tempo acabado!", "Fim de jogo!", MessageBoxButtons.OK, MessageBoxIcon.Stop);
                ChecarFimJogo(ControladorJogo.Instance.OnTempoExpirado());
            }
            else
            {
                //tela de desistencia verifica o fim de jogo por tempo
                while (this.telaDesistenciaAtiva) ;
            }
        }

        internal void OnDesistenciaRequest()
        {
            this.telaDesistenciaAtiva = true;
            var cfm = ExibirConfirmacao("Confirmar desistência", "Tem certeza que deseja desistir?");
            this.telaDesistenciaAtiva = false;

            if (cfm == DialogResult.OK)
            {
                this.tempoExpirado = false;
                TelaPergunta.PararTimers();
                ChecarFimJogo(ControladorJogo.Instance.OnDesistenciaConfirmada());
            }
            else
            {
                //verifica se tempo expirou enquanto estava na janela de cfm
                if (this.tempoExpirado)
                {
                    this.tempoExpirado = false;
                    MessageBox.Show("Tempo acabado!", "Fim de jogo!", MessageBoxButtons.OK, MessageBoxIcon.Stop);
                    ChecarFimJogo(ControladorJogo.Instance.OnTempoExpirado());
                }
                else
                    //volta pra tela de pergunta
                    return;
            }
        }

        internal void OnAlternativaSelecionada(int idx)
        {
            TelaPergunta.PararTimers();
            ChecarFimJogo(ControladorJogo.Instance.OnAlternativaSelecionada(idx));
        }

        internal void OnChute(int idx)
        {
            TelaPergunta.PararTimers();
            ChecarFimJogo(ControladorJogo.Instance.OnChute(idx));
        }

        internal void OnPulo()
        {
            TelaPergunta.PararTimers();
            ChecarFimJogo(ControladorJogo.Instance.OnPulo());
        }

        internal void OnRemocaoAlternativa()
        {
            TelaPergunta.ReiniciarTimers();

            int idx;
            int selIdx;
            ControladorJogo.Instance.OnRemocaoAlternativa(out idx, out selIdx);

            TelaPergunta.DesabilitarAlternativa(idx, selIdx);
        }

        private void ChecarFimJogo(JogoEndCode code)
        {
            switch (code)
            {
                case JogoEndCode.Continua:
                    string enunciadoPergunta;
                    AlternativaCollection alternativas;
                    int tempo;
                    ControladorJogo.Instance.GetPergunta(out enunciadoPergunta, out alternativas, out tempo);
                    ExibirPergunta(enunciadoPergunta, alternativas, tempo);
                    break;                
    
                default:
                    FinalizarJogo(code);
                    break;
            }
        }

        private void FinalizarJogo(JogoEndCode code)
        {
            bool doCadastro = ControladorJogo.Instance.FinalizarJogo();

            string dificuldade;
            float pontuacao;
            ControladorJogo.Instance.GetEndGameInfo(out dificuldade, out pontuacao);
            DoCleanup();

            if (doCadastro)
            {
                RankingDialog cadastroDialog = new RankingDialog();
                cadastroDialog.ShowDialog();
                ControladorRanking.Instance.OnCadastro(pontuacao, dificuldade, apelido);
            }
            ExibirTelaFinal(code);
        }

        private void DoCleanup()
        {
            Configuracao.DoCleanup();
            TelaPergunta.DoCleanup();
        }

        internal void Exit()
        {
            Application.Exit();
        }
    }
}
